05. StatisticsViewModelTest

In the next step, you'll be writing tests for the StatisticViewModel. As a reminder, the StatisticViewModel holds all the data and does all of the calculations for the Statistics Screen:

To set things up for testing the StatisticViewModel, you'll need to make two code changes:

  1. Update StatisticViewModel so that you can inject the fake repository. This is a review of what you did in 5.2 Testing: Intro to Test Doubles when you used the fake repository.
  2. Do the standard test setup for StatisticViewModelTest.

Both of these are review and unrelated to coroutine timing, so feel free to copy/paste.

Step 1: Update StatisticsViewModel for Dependency Injection

  1. Open StatisticsViewModel.
  2. Change the constructor of StatisticsViewModel to take in TasksRepository instead of constructing it inside the class, so that you can inject a fake repository for testing:

StatisticsViewModel.kt

// REPLACE
class StatisticsViewModel(application: Application) : AndroidViewModel(application) {

    private val tasksRepository = (application as TodoApplication).taskRepository

    // Rest of class
}

// WITH

class StatisticsViewModel(
    private val tasksRepository: TasksRepository
) : ViewModel() { 
    // Rest of class 
}
  1. At the bottom of the StatisticsViewModel file, outside the class, add a TasksViewModelFactory which takes in a plain TasksRepository:

StatisticsViewModel.kt

@Suppress("UNCHECKED_CAST")
class StatisticsViewModelFactory (
    private val tasksRepository: TasksRepository
) : ViewModelProvider.NewInstanceFactory() {
    override fun <T : ViewModel> create(modelClass: Class<T>) =
        (StatisticsViewModel(tasksRepository) as T)
}
  1. Update StatisticsFragment to use the factory.

StatisticsFragment.kt

// REPLACE
private val viewModel by viewModels<TasksViewModel>()

// WITH

private val viewModel by viewModels<StatisticsViewModel> {
    StatisticsViewModelFactory(
        (requireContext().applicationContext as TodoApplication).taskRepository
    )
}
  1. Run your application code and navigate to the StatisticsFragment to make sure your statistics screen works just like before.

Step 2: Create StatisticsViewModelTest

  1. Open StatisticsViewModel.kt.
  2. Right-click on the StatisticsViewModel class name and select Generate, then Test.
  3. Follow the prompts to create StatisticsViewModelTest in the test source set.

Follow the steps below to set up your StatisticsViewModel test as you've done previously. This is a good review of what goes into a view model test:

  1. Add the InstantTaskExecutorRule since you are testing Architecture Components.
  2. Add the MainCoroutineRule since you are testing coroutines and view models.
  3. Create fields for the subject under test (StatisticsViewModel) and test doubles for its dependencies (FakeTestRepository).
  4. Create a @Before method that sets up the subject under test and dependencies.

Your test should look like this:

StatisticsViewModelTest.kt

@ExperimentalCoroutinesApi
class StatisticsViewModelTest {

    // Executes each task synchronously using Architecture Components.
    @get:Rule
    var instantExecutorRule = InstantTaskExecutorRule()

    // Set the main coroutines dispatcher for unit testing.
    @ExperimentalCoroutinesApi
    @get:Rule
    var mainCoroutineRule = MainCoroutineRule()

    // Subject under test
    private lateinit var statisticsViewModel: StatisticsViewModel

    // Use a fake repository to be injected into the view model.
    private lateinit var tasksRepository: FakeTestRepository

    @Before
    fun setupStatisticsViewModel() {
        // Initialise the repository with no tasks.
        tasksRepository = FakeTestRepository()

        statisticsViewModel = StatisticsViewModel(tasksRepository)
    }
}